import { FlightRecords } from '../compute/flightRecords';
import { FlightRecordView } from  '../view/flight_log/flightLog';

function createPendant(context) {
  let t0 = new P(context);
  global.t0 = t0;

  let pendant = new context.Pendant({
    require : ['zrender'],
    init : (libs, args) => t0.init(libs, args),
    destroy : () => t0.destroy(),

    // custom function
    collectInfo : () => t0.collectInfo(),
    onMessage : (key, value) => t0.onMessage(key, value),
  });
  t0.sendStatus = () => pendant.sendStatus();
  return pendant;
}

const supportParams = [
  { method: 'latest', supports: ['offset', 'count'] },
  { method: 'year', supports: ['offset', 'count', 'year'] },
  { method: 'conditions', supports: ['offset', 'count', 'vehicles', 'orbits', 'sites', 'important', 'tags'] },
];

class P {
  constructor(context) {
    this.context = context;
    this.records = new FlightRecords({ assetPath: context.assetPath });
  }

  init(libs, args) {
    this.view = new FlightRecordView({
      context: this.context,
      dom: args.dom,
      zrender: libs.zrender,
    });
    this.updateByParams(args.params);

    this.view.on('view/resize', (_, value) => {
      this.arg.view.width = value.width;
      this.arg.view.height = value.height;
      this.sendStatus();
    });
    this.view.startTick();

    this.asyncLoadRecords()
        .then(list => this.view.setRecords(list));
  }

  asyncLoadRecords() {
    if (this.arg.params == null) {
      this.arg.params = {};
    }

    switch(this.arg.method) {
      case "year":
        return this.filterRecordsByYear();
      case "conditions":
        return this.filterRecordsByConditions();
      case "latest": default:
        return this.filterLatestRecords();
    }
  }

  filterLatestRecords() {
    return this.records.getLatestRecords(this.arg.params.offset, this.arg.params.count);
  }

  filterRecordsByYear() {
    const { year, offset, count } = this.arg.params;
    return this.records.load(year)
      .then(list => {
        let startIdx = list.length - (offset + count);
        if (startIdx <= 0) {
          startIdx = 0;
        }
        let endIdx = list.length - offset;
        if (endIdx <= 0) {
          endIdx = 0;
        }
        return list.slice(startIdx, endIdx);
      });
  }

  filterRecordsByConditions() {
    const conditions = [];
    const { vehicles, orbits, sites, important, tags } = this.arg.params;

    if (vehicles) {
      let set = {};
      vehicles.forEach(vText => set[vText] = true);
      conditions.push((item) => item.vehicles.some(v => set[v.type] === true));
    }
    if (orbits) {
      let set = {};
      orbits.forEach(v => set[v] = true);
      conditions.push((item) => set[item.orbit] === true)
    }
    if (sites) {
      let set = {};
      sites.forEach(v => set[v] = true);
      conditions.push((item) => set[item.site] === true)
    }
    if (important) {
      conditions.push((item) => item.isImportant())
    }
    if (tags) {
      let set = {};
      tags.forEach(v => set[v] = true);
      conditions.push((item) => item.tags.some(v => set[v] === true));
    }

    return this.filterRecords(conditions);
  }

  /**
   * @param {((item:FlightItem) => boolean)[]} filters 
   */
  filterRecords(filters) {
    const { offset, count } = this.arg.params;

    return this.records.getLatestRecords(offset, count, (item) => {
      return filters == null || filters.every(filter => filter(item));
    });
  }

  arg = {
    format : "flightLog/cn/ver2021",
    method : "latest",
    params : {
      offset : 0,
      count : 50,
      // year : 2022,
      // vehicles : [],
      // ...
    },
    view : {
      width : 400,
      height : 400,
    },
  };

  collectInfo() {
    return this.arg;
  }

  // onMessage('update', {method:'latest', params:{offset: 0, count: 50}})
  // onMessage('update', {method:'year', params:{year: 2022, offset: 0, count: 50}})
  // onMessage('update', {method:'conditions', params:{tags:['CLEP', '神舟']}})
  onMessage(key, value) {
    switch (key) {
			case 'update': {
        let success = this.onUpdate(value.method, value.params || {});
        if (success) {
          this.asyncLoadRecords()
            .then(list => this.view.setRecords(list));
        } else {
          console.error('update 失败', value.method, value.params);
        }
				this.sendStatus();
      } return;

      // onMessage('print', {bg: 'transparent'})
      case 'print': {
        if (typeof(value.bg) == 'string') {
          this.view.setBgColor(value.bg);
        }
				this.sendStatus();
      } return;
		}
		console.log("flight_log 收到命令", key, value);
  }

  /**
   * init param 仅支持 offset, count, year, vehicles
   */
  updateByParams(initParam) {
    if (initParam == null || initParam.mode == null) {
      return;
    }

    const params = {
      offset : (initParam.offset == null) ? null : parseInt(initParam.offset),
      count : (initParam.count == null) ? null : parseInt(initParam.count),
      year : (initParam.year == null) ? null : parseInt(initParam.year),
      vehicles : (initParam.vehicles == null) ? null :
          (initParam.vehicles == "" ? [] : initParam.vehicles.split(',')),
    };
    this.onUpdate(initParam.mode, params);
  }

  /**
   * @param {string} method
   * @param {object} params
   * @returns 修改是否成功
   */
  onUpdate(method, params) {
    const supports = supportParams.filter(p => p.method === method)[0];
    if (!supports) {
      return false;
    }

    const tmp = {};
    supports.supports.forEach(p => {
      switch (p) {
        case 'offset': {
          tmp[p] = params[p] == null ? 0 : parseInt(params[p]);
          if (tmp[p] < 0) {
            return false;
          }
        } break;
        case 'count': {
          tmp[p] = params[p] == null ? 50 : parseInt(params[p]);
          if (tmp[p] < 0) {
            return false;
          }
        } break;
        case 'year': {
          tmp.year = params.year == null ? new Date().getFullYear() : parseInt(params.year);
          if (tmp.year < 2013) {
            return false;
          }
        } break;
        case 'vehicles': case 'orbits': case 'sites': case 'tags': {
          const array = params[p];
          if (!(array instanceof Array)) {
            return false;
          }
          if (!array.every(v => typeof(v) == 'string')) {
            return false;
          }
          tmp[p] = array;
        } break;
        case 'important': {
          if (params.important) {
            tmp.important = true;
          }
        } break;
        default:
          console.error('flight_log.update 不支持 param =', p);
          return false;
      }
    });

    this.arg.method = method;
    this.arg.params = tmp;
    return true;
  }

  destroy() {
    this.view.destroy();
  }
}

export default createPendant;
